package com.cskaoyan.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author stone
 * @date 2022/07/07 16:07
 */
@Aspect
@Component
public class CustomAspect {

    //@Pointcut在切面组件中的方法上使用
    // 方法名作为其id
    // @Pointcut的value属性写切入点表达式
    @Pointcut("@annotation(com.cskaoyan.anno.CountTime)")
    public void mypointcut() {
    }

    // 通知注解的value属性：
    //     1. 可以直接写切入点表达式
    //     2. 可以引用切入点的方法名 → 后面有一对括号
    // 切面组件中的方法名是任意的
    //@Before("@annotation(com.cskaoyan.anno.CountTime)")
    @Before("mypointcut()")
    public void before(JoinPoint joinPoint) {
        //通过JoinPoint拿到信息
        Object proxy = joinPoint.getThis(); // 代理对象
        Object target = joinPoint.getTarget(); //委托类对象

        Signature signature = joinPoint.getSignature(); //方法的信息
        String name = signature.getName(); //方法名
        System.out.println("方法名：" + name);

        // 拿到参数
        Object[] args = joinPoint.getArgs();

        System.out.println("before通知执行的方法");
    }

    @After("mypointcut()")
    public void after() {
        System.out.println("after通知执行的方法");
    }

    // Around通知 → 是围绕委托类方法的执行的
    // 类似于InvocationHandler的invoke和MethodInterceptor的invoke
    // 里面也包含了委托类方法的调用 👉 通过ProceedingJoinPoint提供的方法可以执行委托类的方法
    @Around("mypointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around的前半部分");
        //执行委托类方法，类似于method.invoke(instance,args)
        // methodInvocation.proceed()
        Object[] args = joinPoint.getArgs();
        if ("add".equals(joinPoint.getSignature().getName())) {
            args[0] = (int)args[0] + 100;
            args[1] = (int)args[1] + 100;
        }

        Object proceed = null;
        try {
            //proceed = joinPoint.proceed();
            proceed = joinPoint.proceed(args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {

        }
        System.out.println("Around的后半部分");
        return proceed;
    }

    // AfterReturning通知可以获得委托类方法return的值
    @AfterReturning(value = "mypointcut()",returning = "result")
    public void afterReturning(Object result) {
        System.out.println("AfterReturning通知:" + result);
    }

    @AfterThrowing(value = "mypointcut()",throwing = "exception")
    public void afterThrowing(Exception exception) {
        System.out.println("抛出的异常：" + exception.getMessage());
    }
}
